﻿using System;
using System.IO;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Ooaavee.Scripting;
using Ooaavee.TestTools;

namespace UnitTests.Ooaavee.Scripting
{
    /// <summary>
    /// Tests Script class.
    /// </summary>
    [TestClass]
    public class ScriptTest : TestBase
    {
        /// <summary>
        /// Tests Run method.
        /// </summary>
        [TestMethod]
        public void RunTest1CSharp()
        {
            const string codeLines = @"return 5 * 5;";

            int result = Script.Run<int>(codeLines);

            Assert.AreEqual(25, result, "5 * 5 == 25");
        }

        /// <summary>
        /// Tests Run method.
        /// </summary>
        [TestMethod]
        public void RunTest1VisualBasic()
        {
            using (LanguageScope.Get(Language.VisualBasic))
            {
                const string codeLines = @"Return 5 * 5";

                int result = Script.Run<int>(codeLines);

                Assert.AreEqual(25, result, "5 * 5 == 25");                
            }            
        }

        /// <summary>
        /// Tests Run method.
        /// </summary>
        [TestMethod]
        public void RunTest2CSharp()
        {
            const string codeLines = @"return 5 * (int)Parameters[0];";

            int result1 = Script.Run<int>(codeLines, 1);
            int result2 = Script.Run<int>(codeLines, 2);
            int result3 = Script.Run<int>(codeLines, 3);

            Assert.AreEqual(5, result1, "5 * 1 == 5");
            Assert.AreEqual(10, result2, "5 * 2 == 10");
            Assert.AreEqual(15, result3, "5 * 3 == 15");
        }

        /// <summary>
        /// Tests Run method.
        /// </summary>
        [TestMethod]
        public void RunTest2VisualBasic()
        {
            using (LanguageScope.Get(Language.VisualBasic))
            {
                const string codeLines = @"Return 5 * CInt(Parameters(0))";

                int result1 = Script.Run<int>(codeLines, 1);
                int result2 = Script.Run<int>(codeLines, 2);
                int result3 = Script.Run<int>(codeLines, 3);

                Assert.AreEqual(5, result1, "5 * 1 == 5");
                Assert.AreEqual(10, result2, "5 * 2 == 10");
                Assert.AreEqual(15, result3, "5 * 3 == 15");
            }
        }

        /// <summary>
        /// Tests Run method.
        /// </summary>
        [TestMethod]
        public void RunTest3CSharp()
        {
            const string codeLines = @"return 5 * (int)Parameters[0];";

            using (Script script = Script.Compile(codeLines))
            {
                int result1 = Script.Run<int>(script, 1);
                int result2 = Script.Run<int>(script, 2);
                int result3 = Script.Run<int>(script, 3);

                Assert.AreEqual(5, result1, "5 * 1 == 5");
                Assert.AreEqual(10, result2, "5 * 2 == 10");
                Assert.AreEqual(15, result3, "5 * 3 == 15");                
            }
        }

        /// <summary>
        /// Tests Run method.
        /// </summary>
        [TestMethod]
        public void RunTest3VisualBasic()
        {
            using (LanguageScope.Get(Language.VisualBasic))
            {
                const string codeLines = @"Return 5 * CInt(Parameters(0))";

                using (Script script = Script.Compile(codeLines))
                {
                    int result1 = Script.Run<int>(script, 1);
                    int result2 = Script.Run<int>(script, 2);
                    int result3 = Script.Run<int>(script, 3);
                    
                    Assert.AreEqual(5, result1, "5 * 1 == 5");
                    Assert.AreEqual(10, result2, "5 * 2 == 10");
                    Assert.AreEqual(15, result3, "5 * 3 == 15");
                }
            }
        }

        /// <summary>
        /// Tests Run method.
        /// </summary>
        [TestMethod]
        [ThrowsException(typeof(ScriptCompileException), ExpectedMessage = "error CS1002: ; expected")]
        public void CompileScriptCompileExceptionTest1CSharp()
        {
            Script.Compile(@"return 0");
        }

        /// <summary>
        /// Tests Run method.
        /// </summary>
        [TestMethod]
        [ThrowsException(typeof(ScriptCompileException), ExpectedMessage = "error BC30037: Character is not valid.")]
        public void CompileScriptCompileExceptionTest1VisualBasic()
        {
            using (LanguageScope.Get(Language.VisualBasic))
            {
                Script.Compile(@"Return 0;");
            }
        }

        /// <summary>
        /// Tests Run method.
        /// </summary>
        [TestMethod]
        [ThrowsException(typeof(ScriptRunException), ExpectedMessage = "Failed to run the script. See the inner exception for details.", ExpectedInnerException = typeof(DivideByZeroException), ExpectedInnerExceptionMessage = "Attempted to divide by zero.")]
        public void RunScriptRunExceptionTest1CSharp()
        {            
            Script.Run(@"return 0 / Convert.ToInt32(""0"");");
        }

        /// <summary>
        /// Tests Run method.
        /// </summary>
        [TestMethod]
        [ThrowsException(typeof(ScriptRunException), ExpectedMessage = "Failed to run the script. See the inner exception for details.", ExpectedInnerException = typeof(DivideByZeroException), ExpectedInnerExceptionMessage = "Attempted to divide by zero.")]
        public void RunScriptRunExceptionTest1VisualBasic()
        {
            using (LanguageScope.Get(Language.VisualBasic))
            {
                Script.Run(@"Return 0 \ CInt(""0"")");
            }
        }

        /// <summary>
        /// Tests CompiledAssembly property.
        /// </summary>
        [TestMethod]
        public void CompiledAssemblyTest()
        {
            using (Script script = Script.Compile("return 0;"))
            {
                Assembly assembly = script.CompiledAssembly;
                
                Assert.IsNotNull(assembly);
            }
        }

        /// <summary>
        /// Tests RootDirectory property.
        /// </summary>
        [TestMethod]
        public void RootDirectoryTest()
        {
            using (Script script = Script.Compile("return 0;"))
            {
                DirectoryInfo root = script.RootDirectory;

                Assert.IsTrue(root.Exists, "The root directory should exist.");
            }            
        }

        /// <summary>
        /// Tests that the script runs in its own AppDomain.
        /// </summary>
        [TestMethod]
        public void AppDomainTest()
        {
            AppDomain appDomain = Script.Run<AppDomain>("return AppDomain.CurrentDomain;");
            Assert.AreNotEqual(AppDomain.CurrentDomain, appDomain, "This script must run in its own AppDomain.");
        }

        /// <summary>
        /// Tests Dispose method.
        /// </summary>
        [TestMethod]
        public void DisposeTest()
        {
            Script script = null;
            try
            {
                script = Script.Compile("return 0;");

                bool existsBefore = script.RootDirectory.Exists;

                script.Dispose();

                bool existsAfter = script.RootDirectory.Exists;

                Assert.IsTrue(existsBefore, "The root directory should exist before the Dispose call.");
                Assert.IsFalse(existsAfter, "The root directory should not exist after the Dispose call.");
            } 
            finally
            {
                if (script != null)
                {
                    script.Dispose();
                }
            }
        }

        #region Demo

        [TestMethod]
        public void Demo1CSharp()
        {
            using (LanguageScope.Get(Language.CSharp))
            {
                string result = Script.Run<string>(@"return ""Hello World!"";");
                Console.Out.WriteLine(result);
            }
        }

        [TestMethod]
        public void Demo1VisualBasic()
        {
            using (LanguageScope.Get(Language.VisualBasic))
            {
                string result = Script.Run<string>(@"Return ""Hello World!""");
                Console.Out.WriteLine(result);
            }
        }




        #endregion

        //        [TestMethod]
//        public void NetTest1()
//        {
//            string code = @"string html;
//                            using (WebClient client = new WebClient()) 
//                            { 
//                                html = client.DownloadString(""http://ooaavee.codeplex.com/""); 
//                            }
//                            return html;";

//            string s = Script.Run<string>(code);

//        }

//        [TestMethod]
//        public void NetTest2()
//        {
//            string code = @"string html;
//                            using (WebClient client = new WebClient()) 
//                            { 
//                                html = client.DownloadString((string)Parameters[0]); 
//                            }
//                            return html;";

//            string s = Script.Run<string>(code, "http://ooaavee.codeplex.com/");

//        }

//        [TestMethod]
//        public void NetTest3()
//        {
//            string s = Script.Run<string>("return ToString();");
//        }

//        /// <summary>
//        /// Tests CreateAndExecute method.
//        /// The used script programming language is C#.
//        /// </summary>
//        [TestMethod]
//        public void CreateAndExecuteCsTest1()
//        {
//            //ScriptingContext.Default.Language = Language.CSharp;

//            object[] parameters = new object[] { "Hello ", "world!" };

//            string lines = "return ((string)Parameters[0]) + ((string)Parameters[1]);";


//            object res1 = Script.Run(lines, parameters);            
//            string res2 = Script.Run<string>(lines, parameters);

//            Assert.AreEqual("Hello world!", res1);
//            Assert.AreEqual("Hello world!", res2);
//        }

//        /// <summary>
//        /// Tests CreateAndExecute method.
//        /// The used script programming language is Visual Basic.
//        /// </summary>
//        [TestMethod]
//        public void CreateAndExecuteVbTest1()
//        {
//            //ScriptingContext.Default.Language = Language.VisualBasic;

//            //object[] parameters = new object[] { "Hello ", "world!" };

//            //string lines = "Return Parameters(0) + Parameters(1)";

//            //object res1 = Script.Run(lines, parameters);
//            //string res2 = Script.Run<string>(lines, parameters);

//            //Assert.AreEqual("Hello world!", res1);
//            //Assert.AreEqual("Hello world!", res2);
//        }
    }
}
